import * as ol from "ol";
import * as Layer from "ol/layer";
import { Geometry } from "ol/geom";
import { getMap } from "./instance";
import {
  CLEARABLE_KEY,
  FEATURE_TYPE_KEY,
  FEATURE_TYPES_KEY,
  IS_BASE_LAYER_KEY,
  LAYER_TYPE_KEY,
  VISIBLE_KEY,
} from "./keys";
import * as Source from "ol/source";
import type { RenderFeatureLayerOptions, RenderFeaturesOptions } from "./types";
import { _renderMarkerFeature, renderMarkers } from "./marker";
import { _renderPolygonFeature, renderPolygons } from "./polygon";
import { _renderPolylineFeature, renderPolylines } from "./polyline";
import { _renderCircleFeature, renderCircles } from "./circle";
import { excludeProperties } from "@utils";
import { parseLngLat } from "./utils";
import { log } from "./log";

// 地图元素 id
let featureId = 0;
/**
 * @description: 获取元素 id
 * @returns {nunmber}
 */
export const queryFeatureId = (): number => {
  featureId += 1;
  return featureId;
};
/**
 * @description: 查询元素列表
 * @param {Array<string>} types 类型数组
 * @returns
 */
export const queryFeatures = (types: {
  features?: string[];
  layers?: string[];
}): ol.Feature[] => {
  const result: ol.Feature[] = [];
  const mapInstance = getMap();
  if (!mapInstance) {
    return result;
  }

  const { features = [], layers = [] } = types;
  // 查询图层
  if (Array.isArray(layers)) {
    mapInstance.getAllLayers().forEach((layer) => {
      const layerType = layer.get(LAYER_TYPE_KEY);
      if (!layerType) {
        return;
      }
      if (
        ["default-feature-layer", "default-feature-layer--hidden"].includes(
          layerType
        )
      ) {
        return;
      }
      if (!layers.includes(layerType)) {
        return;
      }
      if (layer instanceof Layer.Vector) {
        if (layer.getSource() instanceof Source.Vector) {
          result.push(...(layer.getSource() as Source.Vector).getFeatures());
        }
      }
    });
  }
  // 查询默认图层
  const renderlayer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer") as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;
  if (renderlayer && Array.isArray(features) && features.length > 0) {
    renderlayer.getSource()?.forEachFeature((feature) => {
      const featureType = feature.get(FEATURE_TYPE_KEY);
      if (featureType && features.includes(featureType)) {
        result.push(feature);
      }
    });
  }

  return result;
};

/**
 * @description: 移除指定元素
 * @param {Object} types 类型数组
 * @returns
 */
export const removeFeatures = (types: {
  features?: string[] | boolean;
  layers?: string[] | boolean;
  overlays?: boolean;
}): void => {
  const mapInstance = getMap();
  if (!mapInstance) {
    return;
  }

  const { features = [], layers = [], overlays = false } = types;

  // 删除图层
  if (layers === true) {
    mapInstance.getAllLayers().forEach((layer) => {
      const layerType = layer.get(LAYER_TYPE_KEY);
      if (!layerType) {
        return;
      }
      if (
        ["default-feature-layer", "default-feature-layer--hidden"].includes(
          layerType
        )
      ) {
        return;
      }
      mapInstance?.removeLayer(layer);
    });
  } else if (Array.isArray(layers) && layers.length > 0) {
    mapInstance.getAllLayers().forEach((layer) => {
      const layerType = layer.get(LAYER_TYPE_KEY);
      if (!layerType) {
        return;
      }
      if (
        ["default-feature-layer", "default-feature-layer--hidden"].includes(
          layerType
        )
      ) {
        return;
      }
      if (layers.includes(layerType)) {
        mapInstance?.removeLayer(layer);
      }
    });
  }

  // 删除元素
  const defaultFeatureLayer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer") as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;
  const hiddenFeatureLayer = mapInstance
    .getAllLayers()
    .find(
      (item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer-hidden"
    ) as Layer.Vector<Source.Vector<ol.Feature<Geometry>>> | undefined;
  if (features === true) {
    defaultFeatureLayer?.getSource()?.clear();
    hiddenFeatureLayer?.getSource()?.clear();
    defaultFeatureLayer?.set(FEATURE_TYPES_KEY, []);
  } else if (Array.isArray(features) && features.length > 0) {
    defaultFeatureLayer?.getSource()?.forEachFeature((feature) => {
      const featureType = feature.get(FEATURE_TYPE_KEY);
      if (featureType && features.includes(featureType)) {
        defaultFeatureLayer.getSource()?.removeFeature(feature);
      }
    });
    hiddenFeatureLayer?.getSource()?.forEachFeature((feature) => {
      const featureType = feature.get(FEATURE_TYPE_KEY);
      if (featureType && features.includes(featureType)) {
        hiddenFeatureLayer.getSource()?.removeFeature(feature);
      }
    });
    defaultFeatureLayer?.set(
      FEATURE_TYPES_KEY,
      (defaultFeatureLayer?.get(FEATURE_TYPES_KEY) ?? []).filter(
        (type: string) => !features.includes(type)
      )
    );
  }

  // 删除弹窗
  if (overlays) {
    mapInstance.getOverlays().clear();
  }
};
/**
 * @description: 清空默认图层元素
 * @returns
 */
export const clearFeatures = (): void => {
  const mapInstance = getMap();
  if (!mapInstance) {
    return;
  }
  // 删除图层
  mapInstance.getAllLayers().forEach((layer) => {
    const layerType = layer.get(LAYER_TYPE_KEY);
    const clearable = layer.get(CLEARABLE_KEY) ?? true;
    if (!layerType) {
      return;
    }
    if (
      ["default-feature-layer", "default-feature-layer--hidden"].includes(
        layerType
      )
    ) {
      return;
    }
    if (!clearable) {
      return;
    }

    mapInstance?.removeLayer(layer);
  });

  // 删除元素
  const defaultFeatureLayer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer") as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;
  defaultFeatureLayer?.getSource()?.clear();
  const hiddenFeatureLayer = mapInstance
    .getAllLayers()
    .find(
      (item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer-hidden"
    ) as Layer.Vector<Source.Vector<ol.Feature<Geometry>>> | undefined;
  hiddenFeatureLayer?.getSource()?.clear();
  defaultFeatureLayer?.set(FEATURE_TYPES_KEY, []);

  // 删除弹窗
  mapInstance.getOverlays().clear();
};
/**
 * @description: 查询元素类型
 * @returns {Array<string>}
 */
export const queryFeatureTypes = (): string[] => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }

  // 默认元素图层
  const defaultFeatureLayer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer") as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;

  return defaultFeatureLayer?.get(FEATURE_TYPES_KEY) ?? [];
};
/**
 * @description: 查询图层类型
 * @param {Object} options 配置项
 * @returns {Array<string>}
 */
export const queryLayerTypes = (
  options: { features?: boolean; heatmap?: boolean; image?: boolean } = {}
): string[] => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }

  const { features = true, heatmap = true, image = true } = options;
  const types: string[] = [];

  // 自定义图层
  mapInstance.getAllLayers().forEach((layer) => {
    const layerType = layer.get(LAYER_TYPE_KEY);
    const isBaseLayer = layer.get(IS_BASE_LAYER_KEY) ?? true;
    if (!layerType) {
      return;
    }
    if (
      ["default-feature-layer", "default-feature-layer--hidden"].includes(
        layerType
      )
    ) {
      return;
    }
    if (!isBaseLayer) {
      return;
    }

    if (layer instanceof Layer.Vector && features) {
      types.push(layerType);
    } else if (layer instanceof Layer.Heatmap && heatmap) {
      types.push(layerType);
    } else if (layer instanceof Layer.Image && image) {
      types.push(layerType);
    }
  });

  return types;
};
/**
 * @description: 查询图层类型
 * @param {Object} options 配置项
 * @returns {Array<string>}
 */
export const queryFeatureAndLayerTypes = (
  options: { features?: boolean; heatmap?: boolean; image?: boolean } = {}
): string[] => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }

  return [...queryFeatureTypes(), ...queryLayerTypes(options)];
};
/**
 * @description: 查询元素是否存在
 * @param {string} featureType 元素类型
 * @returns {boolean}
 */
export const queryFeatureExist = (featureType: string): boolean => {
  if (!featureType) {
    return false;
  }

  return queryFeatureAndLayerTypes().includes(featureType);
};
/**
 * @description: 查询图层是否存在
 * @param {string} layerType 图层类型
 * @returns {boolean}
 */
export const queryLayerExist = (layerType: string): boolean => {
  if (!layerType) {
    return false;
  }

  return queryLayerTypes().includes(layerType);
};
/**
 * @description: 渲染元素
 * @param {RenderFeaturesOptions} options 配置项
 * @returns {Array<ol.Feature>}
 */
export const renderFeatures = (
  options: RenderFeaturesOptions
): ol.Feature[] => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }

  const {
    type,
    markers,
    polygons,
    polylines,
    circles,
    imageStyle,
    fillStyle,
    strokeStyle,
    labelStyle,
    stopClick,
    stopDBClick,
    onClick,
    onDBClick,
    onMouseEnter,
    onMouseLeave,
  } = options;

  return [
    ...renderMarkers({
      type,
      markers,
      imageStyle,
      labelStyle,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    }),
    ...renderPolygons({
      type,
      polygons,
      fillStyle,
      strokeStyle,
      labelStyle,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    }),
    ...renderPolylines({
      type,
      polylines,
      strokeStyle,
      labelStyle,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    }),
    ...renderCircles({
      type,
      circles,
      fillStyle,
      strokeStyle,
      labelStyle,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    }),
  ];
};

/**
 * @description: 渲染元素图层
 * @param {RenderFeatureLayerOptions} options 配置项
 * @returns {Layer.Vector<Source.Vector<ol.Feature<Geometry>>>}
 */
// eslint-disable-next-line max-lines-per-function
export const renderFeatureLayer = (
  options: RenderFeatureLayerOptions
): Layer.Vector<Source.Vector<ol.Feature<Geometry>>> => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }
  const {
    type: layerType,
    markers,
    polygons,
    polylines,
    circles,
    imageStyle: defaultImageStyle,
    fillStyle: defaultFillStyle,
    strokeStyle: defaultStrokeStyle,
    labelStyle: defaultLabelStyle,
    visible = true,
    clear = true,
    stopClick: defaultStopClick,
    stopDBClick: defaultStopDBClick,
    onClick: defaultOnClick,
    onDBClick: defaultOnDBClick,
    onMouseEnter: defaultOnMouseEnter,
    onMouseLeave: defaultOnMouseLeave,
  } = options;

  let layer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === layerType) as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;
  if (!(layer instanceof Layer.Vector)) {
    layer = new Layer.Vector<Source.Vector<ol.Feature<Geometry>>>({
      source: new Source.Vector<ol.Feature<Geometry>>(),
      ...excludeProperties(options, [
        "type",
        "circles",
        "fillStyle",
        "strokeStyle",
        "label",
        "labelStyle",
        "clear",
        "stopClick",
        "stopDBClick",
        "onClick",
        "onDBClick",
        "onMouseEnter",
        "onMouseLeave",
      ]),
    });
    layer.set(LAYER_TYPE_KEY, layerType);
    mapInstance.addLayer(layer);
  }

  log("Render Feature Layer", options);

  if (clear) {
    layer.getSource()?.clear();
  }

  // 渲染标记点
  if (Array.isArray(markers)) {
    markers.forEach(
      ({
        type,
        name,
        position,
        image,
        imageStyle,
        label,
        labelStyle,
        extData,
        stopClick,
        stopDBClick,
        onClick,
        onDBClick,
        onMouseEnter,
        onMouseLeave,
      }) => {
        layer?.getSource()?.addFeature(
          _renderMarkerFeature({
            type,
            layerType,
            name,
            position: parseLngLat(position) as number[],
            image,
            imageStyle: { ...defaultImageStyle, ...imageStyle },
            label,
            labelStyle: { ...defaultLabelStyle, ...labelStyle },
            extData,
            stopClick: stopClick ?? defaultStopClick,
            stopDBClick: stopDBClick ?? defaultStopDBClick,
            onClick: onClick ?? defaultOnClick,
            onDBClick: onDBClick ?? defaultOnDBClick,
            onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
            onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
          })
        );
      }
    );
  } else {
    const {
      type,
      name,
      position,
      image,
      imageStyle,
      label,
      labelStyle,
      extData,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    } = markers;
    layer?.getSource()?.addFeature(
      _renderMarkerFeature({
        type,
        layerType,
        name,
        position: parseLngLat(position) as number[],
        image,
        imageStyle: { ...defaultImageStyle, ...imageStyle },
        label,
        labelStyle: { ...defaultLabelStyle, ...labelStyle },
        extData,
        stopClick: stopClick ?? defaultStopClick,
        stopDBClick: stopDBClick ?? defaultStopDBClick,
        onClick: onClick ?? defaultOnClick,
        onDBClick: onDBClick ?? defaultOnDBClick,
        onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
        onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
      })
    );
  }

  // 渲染多边形
  if (Array.isArray(polygons)) {
    polygons.forEach(
      ({
        type,
        name,
        position,
        fillStyle,
        strokeStyle,
        label,
        labelStyle,
        extData,
        stopClick,
        stopDBClick,
        onClick,
        onDBClick,
        onMouseEnter,
        onMouseLeave,
      }) => {
        layer?.getSource()?.addFeature(
          _renderPolygonFeature({
            type,
            layerType,
            name,
            position: position.map(
              (line) =>
                line
                  .map((lnglat) => parseLngLat(lnglat))
                  .filter((lnglat) => lnglat !== undefined) as number[][]
            ),
            fillStyle: { ...defaultFillStyle, ...fillStyle },
            strokeStyle: { ...defaultStrokeStyle, ...strokeStyle },
            label,
            labelStyle: { ...defaultLabelStyle, ...labelStyle },
            extData,
            stopClick: stopClick ?? defaultStopClick,
            stopDBClick: stopDBClick ?? defaultStopDBClick,
            onClick: onClick ?? defaultOnClick,
            onDBClick: onDBClick ?? defaultOnDBClick,
            onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
            onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
          })
        );
      }
    );
  } else {
    const {
      type,
      name,
      position,
      fillStyle,
      strokeStyle,
      label,
      labelStyle,
      extData,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    } = polygons;
    layer?.getSource()?.addFeature(
      _renderPolygonFeature({
        type,
        layerType,
        name,
        position: position.map(
          (line) =>
            line
              .map((lnglat) => parseLngLat(lnglat))
              .filter((lnglat) => lnglat !== undefined) as number[][]
        ),
        fillStyle: { ...defaultFillStyle, ...fillStyle },
        strokeStyle: { ...defaultStrokeStyle, ...strokeStyle },
        label,
        labelStyle: { ...defaultLabelStyle, ...labelStyle },
        extData,
        stopClick: stopClick ?? defaultStopClick,
        stopDBClick: stopDBClick ?? defaultStopDBClick,
        onClick: onClick ?? defaultOnClick,
        onDBClick: onDBClick ?? defaultOnDBClick,
        onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
        onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
      })
    );
  }

  // 渲染折线
  if (Array.isArray(polylines)) {
    polylines.forEach(
      ({
        type,
        name,
        position,
        strokeStyle,
        label,
        labelStyle,
        extData,
        stopClick,
        stopDBClick,
        onClick,
        onDBClick,
        onMouseEnter,
        onMouseLeave,
      }) => {
        layer?.getSource()?.addFeature(
          _renderPolylineFeature({
            type,
            layerType,
            name,
            position: position
              .map((lnglat) => parseLngLat(lnglat))
              .filter((lnglat) => lnglat !== undefined) as number[][],
            strokeStyle: { ...defaultStrokeStyle, ...strokeStyle },
            label,
            labelStyle: { ...defaultLabelStyle, ...labelStyle },
            extData,
            stopClick: stopClick ?? defaultStopClick,
            stopDBClick: stopDBClick ?? defaultStopDBClick,
            onClick: onClick ?? defaultOnClick,
            onDBClick: onDBClick ?? defaultOnDBClick,
            onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
            onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
          })
        );
      }
    );
  } else {
    const {
      type,
      name,
      position,
      strokeStyle,
      label,
      labelStyle,
      extData,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    } = polylines;
    layer?.getSource()?.addFeature(
      _renderPolylineFeature({
        type,
        layerType,
        name,
        position: position
          .map((lnglat) => parseLngLat(lnglat))
          .filter((lnglat) => lnglat !== undefined) as number[][],
        strokeStyle: { ...defaultStrokeStyle, ...strokeStyle },
        label,
        labelStyle: { ...defaultLabelStyle, ...labelStyle },
        extData,
        stopClick: stopClick ?? defaultStopClick,
        stopDBClick: stopDBClick ?? defaultStopDBClick,
        onClick: onClick ?? defaultOnClick,
        onDBClick: onDBClick ?? defaultOnDBClick,
        onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
        onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
      })
    );
  }

  // 渲染圆形
  if (Array.isArray(circles)) {
    circles.forEach(
      ({
        type,
        name,
        center,
        radius,
        fillStyle,
        strokeStyle,
        label,
        labelStyle,
        extData,
        stopClick,
        stopDBClick,
        onClick,
        onDBClick,
        onMouseEnter,
        onMouseLeave,
      }) => {
        layer?.getSource()?.addFeature(
          _renderCircleFeature({
            type,
            layerType,
            name,
            center: parseLngLat(center) as number[],
            radius,
            fillStyle: { ...defaultFillStyle, ...fillStyle },
            strokeStyle: { ...defaultStrokeStyle, ...strokeStyle },
            label,
            labelStyle: { ...defaultLabelStyle, ...labelStyle },
            extData,
            stopClick: stopClick ?? defaultStopClick,
            stopDBClick: stopDBClick ?? defaultStopDBClick,
            onClick: onClick ?? defaultOnClick,
            onDBClick: onDBClick ?? defaultOnDBClick,
            onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
            onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
          })
        );
      }
    );
  } else {
    const {
      type,
      name,
      center,
      radius,
      fillStyle,
      strokeStyle,
      label,
      labelStyle,
      extData,
      stopClick,
      stopDBClick,
      onClick,
      onDBClick,
      onMouseEnter,
      onMouseLeave,
    } = circles;
    layer?.getSource()?.addFeature(
      _renderCircleFeature({
        type,
        layerType,
        name,
        center: parseLngLat(center) as number[],
        radius,
        fillStyle: { ...defaultFillStyle, ...fillStyle },
        strokeStyle: { ...strokeStyle, ...defaultStrokeStyle },
        label,
        labelStyle: { ...defaultLabelStyle, ...labelStyle },
        extData,
        stopClick: stopClick ?? defaultStopClick,
        stopDBClick: stopDBClick ?? defaultStopDBClick,
        onClick: onClick ?? defaultOnClick,
        onDBClick: onDBClick ?? defaultOnDBClick,
        onMouseEnter: onMouseEnter ?? defaultOnMouseEnter,
        onMouseLeave: onMouseLeave ?? defaultOnMouseLeave,
      })
    );
  }

  layer.setVisible(visible);

  return layer;
};

/**
 * @description: 显示或渲染元素图层
 * @param {RenderFeatureLayerOptions} options 配置项
 * @returns {Layer.Vector<Source.Vector<ol.Feature<Geometry>>>}
 */
export const showOrRenderFeatureLayer = (
  options: RenderFeatureLayerOptions
): Layer.Vector<Source.Vector<ol.Feature<Geometry>>> => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }
  const { type: layerType, visible = true, clear = false } = options;

  const layer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === layerType) as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;
  if (layer instanceof Layer.Vector && clear === false) {
    log("Change Feature Layer Visible", options);
    layer.setVisible(visible);
    return layer;
  }

  return renderFeatureLayer(options);
};
/**
 * @description: 显示指定元素显隐
 * @param {Object} types 类型数组
 * @param {boolean} visible 是否显示
 * @returns
 */
export const setFeaturesVisible = (
  types: {
    features?: string[];
    layers?: string[];
  },
  visible = true
): void => {
  const mapInstance = getMap();
  if (!mapInstance) {
    return;
  }
  const { features = [], layers = [] } = types;
  // 切换图层显隐
  mapInstance
    .getAllLayers()
    .filter((layer) => {
      const layerType = layer.get(LAYER_TYPE_KEY);
      if (!layerType) {
        return false;
      }
      if (
        ["default-feature-layer", "default-feature-layer--hidden"].includes(
          layerType
        )
      ) {
        return false;
      }
      return layers.includes(layerType);
    })
    .forEach((layer) => layer.setVisible(visible));

  // 切换元素显隐
  const defaultFeatureLayer = mapInstance
    .getAllLayers()
    .find((item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer") as
    | Layer.Vector<Source.Vector<ol.Feature<Geometry>>>
    | undefined;
  const hiddenFeatureLayer = mapInstance
    .getAllLayers()
    .find(
      (item) => item.get(LAYER_TYPE_KEY) === "default-feature-layer-hidden"
    ) as Layer.Vector<Source.Vector<ol.Feature<Geometry>>> | undefined;
  if (features.length > 0 && defaultFeatureLayer && hiddenFeatureLayer) {
    [
      ...(defaultFeatureLayer.getSource()?.getFeatures() ?? []),
      ...(hiddenFeatureLayer.getSource()?.getFeatures() ?? []),
    ].forEach((feature) => {
      const featureType = feature.get(FEATURE_TYPE_KEY);
      const featureVisible = feature.get(VISIBLE_KEY) ?? true;
      if (
        featureType &&
        features.includes(featureType) &&
        featureVisible !== visible
      ) {
        feature.set(VISIBLE_KEY, visible);
        if (visible) {
          defaultFeatureLayer.getSource()?.addFeature(feature);
          hiddenFeatureLayer.getSource()?.removeFeature(feature);
        } else {
          hiddenFeatureLayer.getSource()?.addFeature(feature);
          defaultFeatureLayer.getSource()?.removeFeature(feature);
        }
      }
    });
  }
};
